package com.moonciki.artadmin.core.utils.excel;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.util.TypeUtils;
import com.moonciki.artadmin.core.enums.ResponseEnum;
import com.moonciki.artadmin.core.exception.CustomException;
import com.moonciki.artadmin.core.utils.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * excel 工具
 */
@Slf4j
public class ExcelUtils {

    /**
     * 检查日期是否超过限制
     * @param checkDate
     * @return
     */
    public static boolean checkMaxDate(Date checkDate){
        boolean checkPass = true;

        String maxDateStr = "9999-12-31 23:59:59";

        Date maxDate = DateUtil.parseDate(maxDateStr, DateUtil.date_time_format);

        if(checkDate.after(maxDate)){
            checkPass = false;
        }
        return checkPass;
    }

    /**
     *  excel字符串转DATE
     * @param dateStr
     * @return
     * @throws Exception
     */
    public static Date strongStrToData(String dateStr) throws Exception{
        //年月日时分秒毫秒
        String[] formatArray = {"y", "M", "d", "H", "m", "s", "S"};
        //yyyy-MM-dd HH:mm:ss,SSS
        String[] splitArray = {"-", "-", " ", ":", ":", ",", ""};
        int[] partSizeArray = {4, 2, 2, 2, 2, 2, 3};

        char[] charArray = dateStr.toCharArray();
        StringBuilder dateStrBuilder = new StringBuilder();
        StringBuilder formatBuilder = new StringBuilder();
        int part = 0;

        int nowPartSize = 0;
        for(char oneChar : charArray){
            int partSize = partSizeArray[part];
            String nowSpliter = splitArray[part];

            //判断是否改变part
            if(!Character.isDigit(oneChar) || nowPartSize >= partSize){
                dateStrBuilder.append(nowSpliter);
                formatBuilder.append(nowSpliter);

                part++;
                nowPartSize = 0;

                //判断是否超过标识
                if(part >= formatArray.length){
                    throw CustomException.createException(ResponseEnum.class_type_error.info("日期格式错误"));
                }
            }

            //partSize = partSizeArray[part];

            if(Character.isDigit(oneChar)){
                dateStrBuilder.append(oneChar);
                String formatPart = formatArray[part];
                formatBuilder.append(formatPart);

                nowPartSize ++;
            }
        }

        String newDateStr = dateStrBuilder.toString();
        String formatType = formatBuilder.toString();
        Date resultDate = DateUtil.parseDate(newDateStr, formatType);

        if(!checkMaxDate(resultDate)){
            throw CustomException.createException(ResponseEnum.class_type_error.info("日期格式错误"));
        }

        return resultDate;
    }

    /**
     * excel常规格式日期转java日期
     * @param dateObj
     * @return
     */
    public static Date strongDoubleToDate(Double dateObj){
        Date resultDate = org.apache.poi.ss.usermodel.DateUtil.getJavaDate(dateObj);

        if(!checkMaxDate(resultDate)){
            throw CustomException.createException(ResponseEnum.class_type_error.info("日期格式错误"));
        }

        return resultDate;
    }

    public static Date parseCellDate(Object dateObj) throws Exception{
        Date result = null;
        if (dateObj == null){

        }else if(dateObj instanceof Date){
            result = (Date)dateObj;

        }else if(dateObj instanceof String){
            String dateStr = (String) dateObj;

            if(StringUtils.isNotBlank(dateStr)) {
                result = strongStrToData((String) dateObj);
            }
        }else if(dateObj instanceof BigDecimal){
            Double dateDouble = ((BigDecimal)dateObj).doubleValue();
            result = strongDoubleToDate(dateDouble);
        }else{
            //error
            throw CustomException.createException(ResponseEnum.class_type_error.info("日期格式错误"));
        }

        return result;
    }


    /**
     * 类字段赋值验证
     *
     * @param clazz
     * @param fieldName
     * @param fieldValue
     * @return
     */
    public static boolean fastJsonValidate(Class clazz, String fieldName, Object fieldValue) {

        boolean flag = true;

        if (fieldValue != null) {

            try {
                Field field = clazz.getDeclaredField(fieldName);

                if (field != null) {

                    Class typeClazz = field.getType();

                    if (typeClazz != null) {
                        if (typeClazz.isAssignableFrom(Date.class)) {
                            //nothing to do

                        } else if (typeClazz.isAssignableFrom(Boolean.class)) {
                            TypeUtils.castToBoolean(fieldValue);

                        } else if (typeClazz.isAssignableFrom(String.class)) {
                            TypeUtils.castToString(fieldValue);

                        } else if (typeClazz.isAssignableFrom(Double.class)) {
                            TypeUtils.castToDouble(fieldValue);

                        } else if (typeClazz.isAssignableFrom(Float.class)) {
                            TypeUtils.castToFloat(fieldValue);

                        } else if (typeClazz.isAssignableFrom(Byte.class)) {
                            TypeUtils.castToByte(fieldValue);

                        } else if (typeClazz.isAssignableFrom(Short.class)) {
                            TypeUtils.castToShort(fieldValue);

                        } else if (typeClazz.isAssignableFrom(Integer.class)) {
                            TypeUtils.castToInt(fieldValue);

                        } else if (typeClazz.isAssignableFrom(Long.class)) {
                            TypeUtils.castToLong(fieldValue);

                        } else {
                            throw CustomException.createException(ResponseEnum.sys_error.info("字段类型错误"));
                        }
                    }

                }
            } catch (Exception e) {
                log.info("Validate Error : ", e);
                flag = false;
            }

        }
        return flag;
    }

    /**
     * 按列顺序序列化对象，读 excel 用
     *
     * @param columnNameArray
     * @param columnValueArray
     * @param objClass
     * @return
     */
    public static <T> T parseArrayToObj(String[] titleArray, String[] columnNameArray, Object[] columnValueArray, Class<T> objClass) {

        StringBuilder builder = new StringBuilder();

        int errorCount = 0;
        for (int i = 0; i < columnNameArray.length; i++) {
            String titleName = titleArray[i];
            String columnName = columnNameArray[i];
            Object columnValue = columnValueArray[i];

            if (StringUtils.isNotBlank(columnName) && columnValue != null) {
                boolean val = fastJsonValidate(objClass, columnName, columnValue);

                if (!val) {
                    if (errorCount > 0) {
                        builder.append(";");
                    }
                    errorCount++;
                    builder.append(titleName + "格式错误");
                }
            }
        }

        if (builder.length() > 0) {
            throw CustomException.createException(ResponseEnum.sys_error.info(), builder.toString());
        }

        Map<String, Object> objMap = new HashMap<>();


        for (int i = 0; i < columnNameArray.length; i++) {

            String columnName = columnNameArray[i];
            Object objValue = columnValueArray[i];

            if (StringUtils.isNotBlank(columnName) && objValue != null) {
                objMap.put(columnName, objValue);
            }
        }

        String valueJson = JSON.toJSONString(objMap);
        T parseObj = JSON.parseObject(valueJson, objClass);

        return parseObj;
    }

    public static Object[] objToExcelArray(Object obj, String[] fieldArray){

        Object[] excelArray = new Object[fieldArray.length];

        if(obj != null){
            return excelArray;
        }

        /*
        Map<>

        JSONObject jsonObj = (JSONObject)JSON.toJSON(obj);

        int i = 0;
        for(String oneField: fieldArray){

            Class<?> aClass = obj.getClass();

            aClass.getField("");


            if(value == null){
                //nothing to do
            }else if(value instanceof Boolean){
                Boolean trueValue = (Boolean) value;
                cell.setCellValue(trueValue);
            }else if (value instanceof Integer) {
                Integer trueValue = (Integer)value;
                cell.setCellValue(trueValue);
            } else if(value instanceof Double){
                Double trueValue = (Double)value;
                cell.setCellValue(trueValue);
            } else if(value instanceof Short){
                Short trueValue = (Short)value;
                cell.setCellValue(trueValue);
            } else if(value instanceof String){
                String trueValue = (String)value;
                cell.setCellValue(trueValue);
            } else{
                String trueValue = value + "";
                cell.setCellValue(trueValue);
            }


            i++;
        }
        */

        return excelArray;

    }


}

